# -*- coding: UTF-8 -*-
# 作者： 磊
# @Time：2022/5/4
import json
import re
import jsonpath
import requests

from Demo07.common.yaml_util import read_config_yaml, read_extract_yaml, write_extract_yaml


class RequestsUtil:

    #类变量，通过    请求方式的封装
    session =requests.session()  #获取session对话

    def __init__(self):
        # 读取yaml文件的公共的url数据
        self.base_url=""
        self.last_headers = {}

    # 约定请求规范
    def analysis_yaml(self,caseinfo):
            caseinfo_keys=dict(caseinfo).keys()
            # 判断yaml文件中是否有一级关键字
            if 'name' in caseinfo_keys and 'base_url' in caseinfo_keys and'request' in caseinfo_keys and 'validate' in caseinfo_keys:
                # 判断是否有二级关键字
                request_keys=dict(caseinfo['request']).keys()
                if  'method' in request_keys and 'url' in request_keys:

                    self.base_url=caseinfo['base_url']

                    # 请求头和参数,w文件不能去约定
                    method=caseinfo['request']['method']
                    del caseinfo['request']['method']


                    url=caseinfo['request']['url']
                    del caseinfo['request']['url']

                    # aaa=[]
                    # for key in dict(caseinfo.items()):
                    #     aaa.append(key)
                    # print(aaa)

                    headers=None
                    #是否有headers
                    if jsonpath.jsonpath(caseinfo,'$..headers'):#jsonpath方式取值"$."代表根目录，"$.."代表任意层级下的值
                        headers=caseinfo['request']['headers']
                        del caseinfo['request']['headers']

                    files = None
                    if jsonpath.jsonpath(caseinfo,'$..files'):
                        files = caseinfo['request']['files']
                        for key,value in dict(files).items():
                            files[key] = open(value,'rb')

                        del caseinfo['request']['files']
                    # 我们应该把method，url headers，files，从caseinfo中去掉后把剩余的参数传给kwargs
                    # caseinfo传给下面的参数有['name', 'base_url', 'request', 'validate']，要不人

                    res=self.send_request(method=method,
                                      url=url,
                                      headers=headers,
                                      files=files,
                                      **caseinfo['request'])
                    # 返回json的数据方式方便提取,既要支持正则表达式，有要支持json
                    return_data=res.json()  #前提是要返回json数据
                    return_text=res.text

                    # 输出请求的响应数据
                    print("===================输出请求的响应数据==========================")
                    print(return_text)
                    status_code=res.status_code


                    # 提取响应接口关联的变量,结果关联的话必须使用一级关键字extract，及支持json，又支持正则
                    if 'extract' in caseinfo_keys:
                        for key,value in dict(caseinfo['extract']).items():
                            # 正则提取
                            if '(.+?)' in value or '(.*?)' in value:
                                ze_value=re.search(value,return_text)
                                # print(ze_value)
                                if ze_value:
                                    extract_data = {key:ze_value.group(1)}
                                    write_extract_yaml(extract_data)
                            else: #json的提取
                                extract_data = {key:return_data[value]}
                                write_extract_yaml(extract_data)


                else:
                    print("一级关键字下必须要有二级级关键字method,url")
            else:
                print("必须要有四个一级关键字name,base_url,request,validate")


    # 替换值 通过{{.....}}：,data肯是url， 也可以是参数（字典，字典包含列表，也可以是请求头的字典），所以需要判断下格式
    def replace_value(self,data):
        # 不管是什么类型的数据，通用转换成str的形式
        if data and isinstance(data,dict): #如果这个data是dict，转换为字符串
            str_data = json.dumps(data)
        else:
            str_data = data

        # 替换值
        for a in range(1, str_data.count('{{') + 1):
            if "{{" in str_data and "}}" in str_data:
                start_index = str_data.index("{{")
                end_index = str_data.index("}}",start_index) #从start_index坐标开始找下一个结束的}}
                old_value = str_data[start_index:end_index + 2]
                # 旧的值替换成新的值，从read_extract_yaml里面读取的
                new_value = read_extract_yaml(old_value[2:-2])

                # 两替换的值必须是str，否则报错
                str_data = str_data.replace(old_value, new_value)
                # print(str_data)

        #还原数据类型
        if data and isinstance(data,dict):
            data = json.loads(str_data)#原来是字典的话，上面转化成字符串，下面还是转化为字典
        else:
            data = str_data
        # 返回值
        return data

    def send_request(self, method, url,headers=None, **kwargs):
        # 处理method 转换成小写
        self.last_method = str(method).lower()

        # 1、处理基础路径
        self.base_url=self.base_url+self.replace_value(url)

        # 2、处理请求头
        if headers and isinstance(headers, dict):
            self.last_headers = self.replace_value(headers)

        # 3、核心请求数据去如何替换  肯是params，data，json  这个是处理大括号、{{}}
        for key, value in kwargs.items():
            if key in ['params', 'data', 'json']:
                print("替换前的值",kwargs[key])
                # 替换{{}}格式数据
                kwargs[key] = self.replace_value(value)
                print("替换后的值", kwargs[key])

        # 通过session.request可以自动关联cookies
        res = RequestsUtil.session.request(method=method,url=self.base_url,headers=self.last_headers,**kwargs)

        return res

if __name__ == '__main__':
    url ="https://api.weixin.qq.com/cgi-bin/tags/update?access_token={{access_token}}"
    for a in range(1, url.count('{{')+1):
        if "{{" in url and "}}" in  url:
            start_index=url.index("{{")
            end_index = url.index("}}")
            old_value=url[start_index:end_index+2]
            new_value=read_extract_yaml(old_value[2:-2])
            # 两替换的值必须是str，否则报错
            url=url.replace(old_value,new_value)
            print(url)